---
title: Switch to Better Auth
description: How to change the authentication provider to Better Auth.
---

Better Auth is a comprehensive, open-source authentication framework for TypeScript. It is designed to be framework agnostic, but integrates well with Next.js and provides a lot of features out of the box.

## 1. Swap out the `auth` package dependencies

Uninstall the existing Clerk dependencies from the `auth` package...

```sh title="Terminal"
pnpm remove @clerk/nextjs @clerk/themes @clerk/types --filter @repo/auth
```

...and install the Better Auth dependencies:

```sh title="Terminal"
pnpm add better-auth next --filter @repo/auth
```

Additionally, add `@repo/database` to the `auth` package dependencies.

## 2. Update your environment variables

Generate a secret with the following command to add it to the `.env.local` file in each Next.js application (`app`, `web` and `api`):

```sh title="Terminal"
npx @better-auth/cli secret
```

This will add a `BETTER_AUTH_SECRET` environment variable to the `.env.local` file.

## 3. Setup the server and client auth

Update the `auth` package files with the following code:

### Server

```ts title="packages/auth/server.ts"
import { betterAuth } from 'better-auth';
import { nextCookies } from "better-auth/next-js";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { database } from "@repo/database"

export const auth = betterAuth({
  database: prismaAdapter(database, {
    provider: 'postgresql',
  }),
  plugins: [
    nextCookies()
    // organization() // if you want to use organization plugin
  ],
  //...add more options here
});
```

### Client

```ts title="packages/auth/client.ts"
import { createAuthClient } from 'better-auth/react';

export const { signIn, signOut, signUp, useSession } = createAuthClient();
```

Read more in the Better Auth [installation guide](https://www.better-auth.com/docs/installation).

## 4. Update the auth components

Update both the `sign-in.tsx` and `sign-up.tsx` components in the `auth` package to use the `signIn` and `signUp` functions from the `client` file.

### Sign In

```tsx title="packages/auth/components/sign-in.tsx"
"use client";

import { signIn } from '../client';
import { useState } from 'react';

export const SignIn = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <form
      onSubmit={async (e) => {
        e.preventDefault();
        await signIn.email({
          email,
          password,
        })
      }}
    >
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Sign in</button>
    </form>
  );
}
```

### Sign Up
  
```tsx title="packages/auth/components/sign-up.tsx"
"use client";

import { signUp } from '../client';
import { useState } from 'react';

export const SignUp = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [name, setName] = useState("");

  return (
    <form
      onSubmit={async (e) => {
        e.preventDefault();
        await signUp.email({
          email,
          password,
          name
        })
      }}
    >
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <button type="submit">Sign up</button>
    </form>
  );
}
```

You can use different sign-in methods like social providers, phone, username etc. Read more about Better Auth [basic usage](https://better-auth.com/docs/basic-usage).

## 5. Generate Prisma Models

From the root folder, generate Prisma models for Better Auth by running the following command:

```sh title="Terminal"
npx @better-auth/cli generate --output ./packages/database/prisma/schema.prisma --config ./packages/auth/server.ts
```

<Warning>
You may have to comment out the `server-only` directive in `packages/database/index.ts` temporarily. Ensure you have environment variables set.
</Warning>

## 6. Update the Provider file

Better Auth has no concept of a Provider as a higher-order component, so you can either remove it entirely or just replace it with a stub, like so:

```tsx title="packages/auth/provider.tsx"
import type { ReactNode } from 'react';

type AuthProviderProps = {
  children: ReactNode;
};

export const AuthProvider = ({ children }: AuthProviderProps) => children;
```

## 7. Change Middleware

Change the middleware in the `auth` package to the following. The middleware checks for a session cookie and redirects unauthenticated users to the sign-in page. The optional `middlewareFn` parameter allows you to add custom logic before the authentication check:

```tsx title="packages/auth/middleware.ts"
import { getSessionCookie } from "better-auth/cookies";
import type { NextFetchEvent, NextRequest } from "next/server";
import { NextResponse } from "next/server";

export function authMiddleware(
  middlewareFn?: (
    _auth: { req: NextRequest; authorized: boolean },
    request: NextRequest,
    event: NextFetchEvent,
  ) => Promise<Response> | Response,
) {
  return async function middleware(request: NextRequest, event: NextFetchEvent) {
    const sessionCookie = getSessionCookie(request);
    const authorized = Boolean(sessionCookie);

    if (middlewareFn) {
      const response = await middlewareFn(
        { req: request, authorized },
        request,
        event
      );
      if (response && response.headers.get("Location")) {
        return response;
      }
    }

    if (!sessionCookie) {
      return NextResponse.redirect(new URL("/sign-in", request.url));
    }

    return NextResponse.next();
  };
}
```

## 8. Define and add Next.js Handlers to your app

> Unlike `Clerk`, you need to host auth handlers which will retrieve sessions, authenticate requests etc...

```tsx title="packages/auth/handlers.ts"
import 'server-only';
import { toNextJsHandler } from 'better-auth/next-js';

import { auth } from './server';

export const { POST, GET } = toNextJsHandler(auth);
```

```tsx title="apps/app/app/api/auth/[...all.ts]"
export { POST, GET } from '@repo/auth/handlers'
```

## 9. Update your apps

From here, you'll need to replace any remaining Clerk implementations in your apps with Better Auth.

Here is some inspiration:

```tsx
const user = await currentUser();
const { redirectToSignIn } = await auth();

// to

const session = await auth.api.getSession({
  headers: await headers(), // from next/headers
});
if (!session?.user) {
  return redirect('/sign-in'); // from next/navigation
}
// do something with session.user
```

```tsx
const { orgId } = await auth();

// to

const h = await headers(); // from next/headers
const session = await auth.api.getSession({
  headers: h,
});
const orgId = session?.session.activeOrganizationId;
const fullOrganization = await auth.api.getFullOrganization({
  headers: h,
  query: { organizationId: orgId },
});
```

```tsx title="webhooks/stripe/route.ts"
import { clerkClient } from '@repo/auth/server';

const clerk = await clerkClient();
const users = await clerk.users.getUserList();
const user = users.data.find(
  (user) => user.privateMetadata.stripeCustomerId === customerId
);

// to

import { database } from '@repo/database';

const user = await database.user.findFirst({
  where: {
    privateMetadata: {
      contains: { stripeCustomerId: customerId },
    },
  },
});
```

For using organization, check [organization plugin](https://better-auth.com/docs/plugins/organization) and more from the [Better Auth documentation](https://better-auth.com/docs).
